//-------------------------------------------------------------------------------------------------
// Copyright (c) Bradford W. Mott and Flare Contributors
// North Carolina State University, Department of Computer Science
// The IntelliMedia Group
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//-------------------------------------------------------------------------------------------------

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Flare.Display;
using Flare.Events;
using Flare.Text;
using Flare.Media;

using Sprite = Flare.Display.Sprite;

public class SwfTest : MonoBehaviour
{
    private string[] files = {
        "DynamicText",
        "DynamicTextLayout",
        "GradientFill",
        "BlockTest",
        "StaticText",
        "BitmapTest",
        "SymbolDupTest2",
        "Curve",
        "ScriptTest",
        "HoleTest",
        "ExportTest",
        "SceneFrameLabelTest",
        "GotoTest",
        "AS2Test",
        "FlareSoundDemo",
        "SoundEventTest",
        "AlphaScreenTest",
        "LineTest01",
        "MaskingTest"
    };

    private int currentSwf = 0;

    public Texture2D m_texture = null;

    private SwfCameraOverlayPlayer player = null;
 
    private Sound sound;
    private SoundChannel channel;
    
    void Start()
    {
        this.player = GetComponent<SwfCameraOverlayPlayer>();
        Flare.Log.SubsystemFilter = Flare.Subsystem.All;

        ProcessSwf();
    }

    void FSCommandCallback(string command, string parameters)
    {
        Debug.Log("FSCommand(\"" + command + "\", \"" + parameters + "\")");
    }

    void ProcessSwf()
    {
        sound = null;
        
        // Load the current SWF file
        TextAsset asset = Resources.Load(files[currentSwf % files.Length]) as TextAsset;

        // Create a native window with this SWF file
        player.nativeWindow = new Flare.Display.NativeWindow(player.bounds,
            player.transparent, asset.bytes);

        // Activate the window so that it'll process keyboard and mouse events
        player.nativeWindow.Activate();

        player.nativeWindow.AddFSCommandCallback(FSCommandCallback);

        MovieClip clip = player.nativeWindow.stage.GetChildByName("root1") as MovieClip;

        if (files[currentSwf % files.Length].Equals("BlockTest"))
        {
            CreateBlocks();
        }
        else if (files[currentSwf % files.Length].Equals("BitmapTest"))
        {
            CreateBitmapFill();
        }
        else if (files[currentSwf % files.Length].Equals("ExportTest"))
        {
            // Add an event listener to the stage to handle mouse down events
            player.nativeWindow.stage.AddEventListener(MouseEvent.MOUSE_DOWN,
                new EventListener(MouseDownHandler));
        }
        else if (files[currentSwf % files.Length].Equals("SceneFrameLabelTest"))
        {
            clip.AddEventListener(Flare.Events.Event.FRAME_CONSTRUCTED, PrintSceneHandler);
        }
        else if (files[currentSwf % files.Length].Equals("GotoTest"))
        {
            clip.AddEventListener(Flare.Events.Event.FRAME_CONSTRUCTED, GotoHandler);
        }
        else if(files[currentSwf % files.Length].Equals("FlareSoundDemo"))
        {
            LoaderInfo info = this.player.nativeWindow.stage.loaderInfo;
            if (info.applicationDomain.HasDefinition("Quest"))
            {
                sound = info.applicationDomain.InstantiateDefinition<Sound>("Quest");
            }
        }
    }
    
    public void GotoHandler(Flare.Events.Event evt)
    {
        MovieClip clip = evt.target as MovieClip;
        Debug.Log("Current Frame: " + clip.currentFrame);
        if (clip.currentFrame == 50)
        {
            clip.GotoAndPlay(30);
        }
    }

    public void PrintSceneHandler(Flare.Events.Event evt)
    {
        MovieClip clip = evt.target as MovieClip;

        foreach (var s in clip.scenes)
        {
            foreach (var l in s.labels)
            {
                Debug.Log("Scene '" + s.name + "' " + s.numFrames +
                    " Label: '" + l.name + "' " + l.frame);
            }
        }

        for (int i = 0; i < clip.numChildren; ++i)
        {
            MovieClip c = clip.GetChildAt(i) as MovieClip;

            if (c.scenes != null)
            {
                foreach (var s in c.scenes)
                {
                    foreach (var l in s.labels)
                    {
                        Debug.Log("Scene '" + s.name + "' " + s.numFrames +
                            " Label: '" + l.name + "' " + l.frame);
                    }
                }
            }
        }
    }

    void CreateBitmapFill()
    {
        BitmapData bd = new BitmapData(m_texture);
        Sprite sprite = new Sprite();
        sprite.graphics.BeginBitmapFill(bd);
        sprite.graphics.MoveTo(50, 50);
        sprite.graphics.LineTo(50, 250);
        sprite.graphics.LineTo(350, 250);
        sprite.graphics.LineTo(350, 50);
        sprite.graphics.LineTo(50, 50);
        sprite.graphics.EndFill();
        sprite.transform.matrix.tx = 200;
        sprite.transform.matrix.ty = 0;

        player.nativeWindow.stage.AddChild(sprite);
    }

    void CreateBlocks()
    {
        LoaderInfo info = this.player.nativeWindow.stage.loaderInfo;

        // Create "green" container for the addition operator
        Sprite plus = new Sprite();
        plus.graphics.BeginFill(0x001e9900);
        plus.graphics.MoveTo(150, -32);
        plus.graphics.CurveTo(160, -32, 160, 0);
        plus.graphics.CurveTo(160, 32, 150, 32);
        plus.graphics.LineTo(-150, 32);
        plus.graphics.CurveTo(-160, 32, -160, 0);
        plus.graphics.CurveTo(-160, -32, -150, -32);
        plus.graphics.LineTo(150, -32);
        plus.graphics.EndFill();
        plus.transform.matrix.tx = 400;
        plus.transform.matrix.ty = 500;

        // Create a "+" sign to label the addition operator. We would normally use a
        // DynamicText object; however, since those are not implemented yet we'll use a
        // StaticText object defined in the SWF file.
        var plusSign = info.applicationDomain.InstantiateDefinition<DisplayObject>("Plus");
        plusSign.name = "PlusSign";
        plus.AddChild(plusSign);

        // Create the white rounded number entry field
        Sprite number1 = new Sprite();
        number1.graphics.BeginFill(0x00ffffff);
        number1.graphics.MoveTo(50, -22);
        number1.graphics.CurveTo(60, -22, 60, 0);
        number1.graphics.CurveTo(60, 22, 50, 22);
        number1.graphics.LineTo(-50, 22);
        number1.graphics.CurveTo(-60, 22, -60, 0);
        number1.graphics.CurveTo(-60, -22, -50, -22);
        number1.graphics.LineTo(50, -22);
        number1.graphics.EndFill();
        number1.name = "Number1Background";

        // Place a sample number inside the entry field, once again we use a StaticText
        // object defined in the SWF file.
        var numLabel1 = info.applicationDomain.InstantiateDefinition<DisplayObject>("Number");
        number1.AddChild(numLabel1);

        // Position the number entry field and add it to the addition operator
        number1.transform.matrix.tx = -80;
        number1.transform.matrix.ty = 0;
        plus.AddChild(number1);

        // Create the second number entry field and add it to the addition operator
        Sprite number2 = new Sprite();
        number2.graphics.BeginFill(0x00ffffff);
        number2.graphics.MoveTo(50, -22);
        number2.graphics.CurveTo(60, -22, 60, 0);
        number2.graphics.CurveTo(60, 22, 50, 22);
        number2.graphics.LineTo(-50, 22);
        number2.graphics.CurveTo(-60, 22, -60, 0);
        number2.graphics.CurveTo(-60, -22, -50, -22);
        number2.graphics.LineTo(50, -22);
        number2.graphics.EndFill();
        number2.name = "Number2Background";

        var numLabel2 = info.applicationDomain.InstantiateDefinition<DisplayObject>("Number");
        number2.AddChild(numLabel2);

        number2.transform.matrix.tx = 80;
        number2.transform.matrix.ty = 0;
        plus.AddChild(number2);

        // Add the addition operator to the stage
        plus.name = "Addition Operator";
        player.nativeWindow.stage.AddChild(plus);

        TextField field = new TextField();
        field.x = 40;
        field.y = 380;
        field.defaultTextFormat = new TextFormat("Arial", 18, 0x0000ff);
        field.width = 300;
        field.height = 22;
        field.border = true;
        field.borderColor = 0xff0000;
        field.background = true;
        field.backgroundColor = 0xffffff;
        field.text = "Hello World!!!";
        field.type = TextFieldType.INPUT;

        player.nativeWindow.stage.AddChild(field);

        TextField passwd = new TextField();
        passwd.x = 40;
        passwd.y = 410;
        passwd.defaultTextFormat = new TextFormat("Arial", 18);
        passwd.width = 300;
        passwd.height = 22;
        passwd.border = true;
        passwd.borderColor = 0x000000;
        passwd.background = true;
        passwd.backgroundColor = 0xffffff;
        passwd.text = "Secret";
        passwd.type = TextFieldType.INPUT;
        passwd.displayAsPassword = true;

        field.tabIndex = 1;
        passwd.tabIndex = 2;
        player.nativeWindow.stage.AddChild(passwd);

        // Add an event listener to the plus sign to get a script executed each frame
        //plus.AddEventListener(Flare.Events.Event.FRAME_CONSTRUCTED,
        //    new EventListener(FrameHandler));
//        plusSign.AddEventListener(Flare.Events.MouseEvent.MOUSE_DOWN,
//            new EventListener(OperatorMouseHandler));
//        number1.AddEventListener(Flare.Events.MouseEvent.MOUSE_DOWN,
//            new EventListener(OperatorMouseHandler));
//        number2.AddEventListener(Flare.Events.MouseEvent.MOUSE_DOWN,
//            new EventListener(OperatorMouseHandler));

        plus.AddEventListener(Flare.Events.MouseEvent.MOUSE_DOWN,
            new EventListener(OperatorMouseDownHandler));
        
        plus.AddEventListener(Flare.Events.MouseEvent.MOUSE_UP,
            new EventListener(OperatorMouseUpHandler));

        plus.AddEventListener(Flare.Events.MouseEvent.RIGHT_MOUSE_UP,
            new EventListener(OperatorRightMouseUpHandler));
    }

    public void OperatorMouseDownHandler(Flare.Events.Event evt)
    {
        MouseEvent mevt = evt as MouseEvent;
        Sprite op = mevt.currentTarget as Sprite;
        op.StartDrag();
    }

    public void OperatorMouseUpHandler(Flare.Events.Event evt)
    {
        MouseEvent mevt = evt as MouseEvent;
        Sprite op = mevt.currentTarget as Sprite;
        op.StopDrag();
    }

    public void OperatorRightMouseUpHandler(Flare.Events.Event evt)
    {
        MouseEvent mevt = evt as MouseEvent;
        DisplayObject obj = mevt.currentTarget as DisplayObject;

        if (obj.HasEventListener(Flare.Events.Event.FRAME_CONSTRUCTED))
        {
            Debug.Log("Stop Rotating");
            obj.RemoveEventListener(Flare.Events.Event.FRAME_CONSTRUCTED,
                new EventListener(FrameHandler));
        }
        else
        {
            Debug.Log("Start Rotating");
            obj.AddEventListener(Flare.Events.Event.FRAME_CONSTRUCTED,
                new EventListener(FrameHandler));
        }
    }

    public void OperatorMouseHandler(Flare.Events.Event evt)
    {
        MouseEvent mevt = evt as MouseEvent;
        Debug.Log((mevt.currentTarget as DisplayObject).name  + " " + mevt.ToString());
    }

    public void FrameHandler(Flare.Events.Event evt)
    {
        DisplayObject obj = evt.target as DisplayObject;

        // Rotate obj about its origin by 1 degree each frame
        Flare.Geom.Matrix m = new Flare.Geom.Matrix(obj.transform.matrix);
        obj.transform.matrix.Rotate(Mathf.PI / 180.0f);
        obj.transform.matrix.tx = m.tx;
        obj.transform.matrix.ty = m.ty;
    }

    public void MouseDownHandler(Flare.Events.Event evt)
    {
        MouseEvent mevt = evt as MouseEvent;
        Debug.Log(mevt.ToString());

        LoaderInfo info = this.player.nativeWindow.stage.loaderInfo;
        if (info.applicationDomain.HasDefinition("SimpleHole"))
        {
            var obj = info.applicationDomain.InstantiateDefinition<DisplayObject>("SimpleHole");
            obj.x = mevt.stageX;
            obj.y = mevt.stageY;
            obj.scaleX = 0.5f + Random.value;
            obj.scaleY = 0.5f + Random.value;
            player.nativeWindow.stage.AddChild(obj);
            float r = 720f * Random.value - 360f;
            obj.rotation = r;
        }
            
    }

    void OnGUI()
    {
        if (GUI.Button(new Rect(25, 5, 90, 30), "Previous"))
        {
            if (--currentSwf < 0)
            {
                currentSwf = files.Length - 1;
            }
            ProcessSwf();
        }

        if (GUI.Button(new Rect(125, 5, 90, 30), "Next"))
        {
            ++currentSwf;
            ProcessSwf();
        }
        
        if(sound != null)
        {
            if (GUI.Button(new Rect(450, 240, 90, 30), "Play"))
            {
                if(channel == null)
                {
                    channel = sound.Play(0, 0, null);
                }
            }
            
            if (GUI.Button(new Rect(450, 280, 90, 30), "Stop"))
            {
                if(channel != null)
                {
                    channel.Stop();
                    channel = null;
                }
            }
            
            if (GUI.Button(new Rect(450, 200, 90, 30), "Volume Up"))
            {
                if(channel != null && channel.soundTransform.volume < 1.0f)
                {
                    channel.soundTransform = new SoundTransform(
                        channel.soundTransform.volume + 0.1f, channel.soundTransform.pan);
                }
            }
            
            if (GUI.Button(new Rect(450, 320, 90, 30), "Volume Down"))
            {
                if(channel != null && channel.soundTransform.volume > 0)
                {
                    channel.soundTransform = new SoundTransform(
                        channel.soundTransform.volume - 0.1f, channel.soundTransform.pan);
                }
            }
            
            if (GUI.Button(new Rect(550, 260, 90, 30), "Pan Right"))
            {
                if(channel != null && channel.soundTransform.pan < 1.0f)
                {
                    channel.soundTransform = new SoundTransform(
                        channel.soundTransform.volume, channel.soundTransform.pan + 0.1f);
                }
            }
            
            if (GUI.Button(new Rect(350, 260, 90, 30), "Pan Left"))
            {
                if(channel != null && channel.soundTransform.pan > -1.0f)
                {
                    channel.soundTransform = new SoundTransform(
                        channel.soundTransform.volume, channel.soundTransform.pan - 0.1f);
                }
            }
        }
    }
}
